package com.googlecode.gwtbb.util;

import com.googlecode.gwtbb.client.shared.util.ObjectUtils0;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.PropertyUtils;

import java.lang.reflect.InvocationTargetException;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;

/**
 * @author Abraham Grief
 * @version $Id$
 * @since Jun 24, 2008
 */
public class ObjectUtils extends ObjectUtils0 {
	public static boolean nullSafeEquals(Object o1, Object o2) {
		if (o1 == null)
			return o2 == null;
		return o2 != null && o1.equals(o2);
	}

	public static <T> int nullSafeCompareTo(Comparable<T> o1, T o2) {
		if (o1 == null)
			return o2 == null ? 0 : -1;
		if (o2 == null)
			return 1;
		return o1.compareTo(o2);
	}

	public static String nullSafeToString(Object o) {
		return o == null ? null : o.toString();
	}

	public static boolean differ(Object o1, Object o2, Collection<String> properties) {
		try {
			for (String property : properties)
				if (!nullSafeEquals(PropertyUtils.getProperty(o1, property), PropertyUtils.getProperty(o2, property)))
					return true;
			return false;
		} catch (NoSuchMethodException e) {
			throw new IllegalArgumentException(e);
		} catch (IllegalAccessException e) {
			throw new IllegalArgumentException(e);
		} catch (InvocationTargetException e) {
			throw new IllegalArgumentException(e);
		}
	}

	public static LinkedHashSet<String> differentProperties(Object o1, Object o2, Collection<String> properties) {
		try {
			LinkedHashSet<String> differentProperties = new LinkedHashSet<String>(properties.size());
			for (String property : properties)
				if (!nullSafeEquals(PropertyUtils.getProperty(o1, property), PropertyUtils.getProperty(o2, property)))
					differentProperties.add(property);
			return differentProperties;
		} catch (NoSuchMethodException e) {
			throw new IllegalArgumentException(e);
		} catch (IllegalAccessException e) {
			throw new IllegalArgumentException(e);
		} catch (InvocationTargetException e) {
			throw new IllegalArgumentException(e);
		}
	}

	public static LinkedHashMap<String, Object> newPropertyValues(Object oldObj, Object newObj, Collection<String> properties) {
		try {
			LinkedHashMap<String, Object> newPropertyValues = new LinkedHashMap<String, Object>(properties.size());
			for (String property : properties) {
				Object newValue = PropertyUtils.getProperty(newObj, property);
				if (!nullSafeEquals(PropertyUtils.getProperty(oldObj, property), newValue))
					newPropertyValues.put(property, newValue);
			}
			return newPropertyValues;
		} catch (NoSuchMethodException e) {
			throw new IllegalArgumentException(e);
		} catch (IllegalAccessException e) {
			throw new IllegalArgumentException(e);
		} catch (InvocationTargetException e) {
			throw new IllegalArgumentException(e);
		}
	}

	public static void copyProperties(Object dst, Object src) throws IllegalArgumentException {
		try {
			BeanUtils.copyProperties(dst, src);
		} catch (IllegalAccessException e) {
			throw new IllegalArgumentException(e);
		} catch (InvocationTargetException e) {
			throw new IllegalArgumentException(e);
		}
	}

	public static void copyProperties(Object dst, Object src, Collection<String> properties) throws IllegalArgumentException {
		try {
			for (String property : properties)
				PropertyUtils.setProperty(dst, property, PropertyUtils.getProperty(src, property));
		} catch (IllegalAccessException e) {
			throw new IllegalArgumentException(e);
		} catch (InvocationTargetException e) {
			throw new IllegalArgumentException(e);
		} catch (NoSuchMethodException e) {
			throw new IllegalArgumentException(e);
		}
	}

	public static <T> T createShallowCopy(Class<T> newInstanceClass, Object src, Collection<String> properties) throws IllegalArgumentException {
		try {
			T retVal = newInstanceClass.newInstance();
			copyProperties(retVal, src, properties);
			return retVal;
		} catch (InstantiationException e) {
			throw new IllegalArgumentException(e);
		} catch (IllegalAccessException e) {
			throw new IllegalArgumentException(e);
		}
	}
}
